package com.ryan.security.browser;

import com.ryan.security.browser.authentication.SimpleAuthenticationSuccessHandler;
import com.ryan.security.core.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
import com.ryan.security.core.properties.SecurityProperties;
import com.ryan.security.core.validate.code.SmsValidatorCodeFilter;
import com.ryan.security.core.validate.code.ValidatorCodeFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * Created by kaimin on 1/1/2019.
 * time : 15:23
 */
@Configuration
public class BrowserSecutiryConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private AuthenticationSuccessHandler simpleAuthenticationSuccessHandler;
    @Autowired
    private AuthenticationFailureHandler simpleAuthenticationFailHandler;

    @Autowired
    private DataSource dataSource;//是配置在具体的项目里面的数据源信息

    @Autowired
    private UserDetailsService myuserDetailsService;//需要用这个查用户，最后在config里面配置

    //把短信登录的封装加入进来
    @Autowired
    private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;
//    记住我配置

    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository=new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        tokenRepository.setCreateTableOnStartup(false);//JdbcTokenRepositoryImpl里面的脚本会自动执行
        return tokenRepository;//还要配置token过期的配置
    }

    @Bean //使自定义的密码策略生效
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }




    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //设置用户名和密码的filter
        ValidatorCodeFilter validatorCodeFilter=new ValidatorCodeFilter();
        validatorCodeFilter.setAuthenticationFailureHandler(simpleAuthenticationFailHandler);
        validatorCodeFilter.setSecurityProperties(securityProperties);
        validatorCodeFilter.afterPropertiesSet();//初始化方法

        //设置手机登录的filter
        SmsValidatorCodeFilter smsvalidatorCodeFilter=new SmsValidatorCodeFilter();
        smsvalidatorCodeFilter.setAuthenticationFailureHandler(simpleAuthenticationFailHandler);
        smsvalidatorCodeFilter.setSecurityProperties(securityProperties);
        smsvalidatorCodeFilter.afterPropertiesSet();

        http
//                .addFilterBefore(smsvalidatorCodeFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(validatorCodeFilter, UsernamePasswordAuthenticationFilter.class)
//        http
                .formLogin()//表单登录
                //.loginPage("/login.html")//自定义登录页面
                .loginPage("/authentication/require")//自定义登录请求controller
                .loginProcessingUrl("/authentication/form")//使自定义的form表单url让UsernamePasswordAuthenticationFilter知道并生效
//        http.httpBasic()//基本登录 初始默认的
                .successHandler(simpleAuthenticationSuccessHandler)//指定成功登录后的handler
                .failureHandler(simpleAuthenticationFailHandler)//指定失败处理器
                .and().
                rememberMe().//加记住我功能,配置这些即可
                tokenRepository(persistentTokenRepository())//token存的库
                .tokenValiditySeconds(securityProperties.getBrowser().getRemeberMeSeconds())//过期时间
                .userDetailsService(myuserDetailsService)//自定义的用户信息，即可完成记住我
                .and()
                .authorizeRequests().//下面都是授权的配置
               // antMatchers("/login.html").permitAll().//这个url不需要身份认证
                antMatchers("/authentication/require","/authentication/mobile",
                       "/login.html",
                       "/code/*",
                       securityProperties.getBrowser().getLoginPage()).permitAll().//这个url不需要身份认证
                anyRequest().//任何请求
                authenticated()//都需要身份认证
                .and().csrf().disable()//跨域防护功能关闭，后面代码处理过之后再开启
        .apply(smsCodeAuthenticationSecurityConfig)//加入短信的配置
        ;
    }
}
